import 'package:flutter/material.dart';
import 'package:flutter_study/datas/listData.dart';

void main() => runApp(MyApp());

/* ListView生命周期
*  1.子组件的创建：当ListView被创建时根据ListView创建item方式不同，也不同
*     - 采用默认构造的ListView，ListView创建子组件UI元素、状态等都会被创建
*     - 采用build方式，只有在显示时子组件才会被创建
*  2. 在滑出屏幕时，子组件会被销毁，再次划回来就会重新创建
*  3. 避免子组件销毁，不希望子组件滑出屏幕被销毁而是保持状态
*     - 将相关运算、变量值的保存移除到子组件外处理，例如加载网络图片可以在item外下载缓存，当子组件需要显示时，直接从缓存获取
*     - 使用KeepAlive作为子组件的根组件使用，仅当addAutomaticKeepAlives、addRepaintBoundaries为false起作用
*     - 使用AutomaticKeepAlive组件或将addAutomaticKeepAlives 设为true
* */
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: Text('线性列表组件'),
          ),
          body: BuildListView()
          // BuildListView3() // 构建的方式
          // CustomListView() // 自定义ListView
          // SeparatedListView() // 带分割线的ListView
          // SimpleListView(), // 直接盛放子组件
          // ListGenerateContent()
          ),
    );
  }
}

// ListView item自定义，对于ListView item复杂时使用
// 使用childrenDelegate属性渲染布局
class CustomListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.custom(
        itemExtent: 30.0,
        cacheExtent: 0.0, // 预加载在屏幕外的item条数
        childrenDelegate:
            CustomChildDelegate((context, index) => Text('item==>$index')));
  }
}

class CustomChildDelegate extends SliverChildBuilderDelegate {
  CustomChildDelegate(builder) : super(builder);

  // 绘制完毕组件布局时被调用
  @override
  void didFinishLayout(int firstIndex, int lastIndex) {
    super.didFinishLayout(firstIndex, lastIndex);
    debugPrint("Finish! Start at $firstIndex,end at $lastIndex");
  }
}

// 在构建ListView的基础上多了分割线
class SeparatedListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.separated(
        itemBuilder: (context, index) => Text('item--$index'),
        separatorBuilder: (context, index) => Divider(
              color: Colors.red,
              // 不会加粗线而是增加线占据的高度，即控件高度
              height: 50,
              // 添加前后间距
              indent: 30,
              endIndent: 30,
              // 改变线自身粗度
              thickness: 10,
            ),
        itemCount: 30);
  }
}

// 1.构建ListView，在child多的情况下使用，采用懒加载的方式
class BuildListView extends StatelessWidget {
  final List<String> datas = List.generate(20, (index) => "数据 $index");

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (BuildContext context, int index) {
        // 侧滑删除
        return Dismissible(
          key: Key("${datas[index]}"),
          background: Container(
            color: Colors.redAccent,
          ),
          direction: DismissDirection.endToStart,
          child: Text('${datas[index]}'),
          onDismissed: (direction) {
            /*ScaffoldMessenger.of(context)
                .showSnackBar(SnackBar(content: Text('${datas[index]}')));*/
            datas.removeAt(index);
          },
        );
      },
      itemCount: datas.length, // 子View数量，写null则child无限多
      itemExtent: 30, // 子View高度，为了提高效率，尽量写固定值
    );
  }
}

// 2.构建ListView 抽离ListView children 方法
class BuildListView2 extends StatelessWidget {
  List<Widget> _getChildrenDatas() {
    List<Widget> list = [];
    for (int i = 0; i < 20; i++) {
      list.add(ListTile(
        title: Text("data:$i"),
      ));
    }
    return list;
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: EdgeInsets.all(12),
      children: this._getChildrenDatas(),
    );
  }
}

// 3.构建ListView 使用外部文件的数据
class BuildListView3 extends StatelessWidget {
  List<Widget> _getChildrenDatas() {
    var tempList = listData.map((value) {
      return ListTile(
        title: Text(value["title"]),
        subtitle: Text(value["author"]),
        leading: Image.network(
          value["imageUrl"],
          width: 30,
          height: 30,
        ),
      );
    });
    debugPrint("tempList==>$tempList");
    debugPrint("tempList.toList==>${tempList.toList()}");
    //map转换后 tempList数据格式为(1,2,3)使用toList将其转换为[1,2,3]
    return tempList.toList();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: EdgeInsets.all(12),
      children: this._getChildrenDatas(),
    );
  }
}

// 直接盛放子组件创建ListView，类似于ScrollView+Column
class SimpleListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      // ListView的item默认都包装在AutomaticKeepAlives组件中，这样子组件超出屏幕不会被GC回收，
      // 当不需要这样做时设置false，不需要元素保持活动，即元素本身维护KeepAlive状态换个自定义滚动时用到
      addAutomaticKeepAlives: false,
      // 如果item很复杂，需要大量运算，为了优化显示性能，要避免重绘或运算
      // ListView提供RepaintBoundary组件包裹item避免重绘并设置值为true,如果为false则让item自身维护状态
      addRepaintBoundaries: false,
      scrollDirection: Axis.vertical,
      padding: EdgeInsets.all(8.0),
      // 控制整个ListView长度，默认为false，当嵌套在另一个滚动组件中，指定为true解决滑动冲突
      shrinkWrap: true,
      // 防止滑动冲突
      primary: true,
      physics: BouncingScrollPhysics(),
      children: [
        Container(
          color: Colors.redAccent,
          height: 200.0,
        ),
        Container(
          color: Colors.blue,
          height: 200.0,
        ),
        Container(
          color: Colors.yellow,
          height: 200.0,
        ),
        Container(
          color: Colors.deepPurple,
          height: 200.0,
        ),
      ],
    );
  }
}

// 使用默认构造方法创建ListView，用于ListView有比较少且确定个数的子View时使用
// 该方式会尽可能多的加载item进行展示，如果子item不确定个数不建议使用默认构造
class ListGenerateContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      // reverse: true, 反转数据
      // 设置item固定高度，如果不指定根据item自身高度决定，每个item高度可能不同
      itemExtent: 50,
      children: List.generate(100, (index) {
        return ListTile(
          leading: Icon(Icons.people),
          trailing: Icon(Icons.delete),
          title: Text("联系人 $index"),
        );
      }),
    );
  }
}
